package org.sam.swing.table.defaultImpl;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.sam.swing.table.DataAccessProvider;

/**
 * 使用反射实现的默认数据访问工具
 * 
 * @author sam
 *
 * @param <E>
 */
public class DefaultDataAcesProvider implements DataAccessProvider {

	/**
	 * method不存在的时候，使用字段直接访问方式
	 */
	private Field field;

	/**
	 * 函数访问方式
	 */
	private Method getMethod;

	/**
	 * 数据写入函数
	 */
	private Method setMethod;

	/**
	 * 使用反射实现的默认数据访问工具
	 * 
	 * @param name
	 */
	public DefaultDataAcesProvider(Class<?> cls, String name) {
		try {
			try {

				getMethod = MethodUtils.getAccessibleMethod(cls,
						"get" + name.substring(0, 1).toUpperCase() + name.substring(1));

			} catch (Exception ex) {
				getMethod = null;
			}

			if (getMethod == null) {
				try {
					getMethod = MethodUtils.getAccessibleMethod(cls,
							"is" + name.substring(0, 1).toUpperCase() + name.substring(1));
				} catch (Exception ex) {
					getMethod = null;
				}
			}

			if (getMethod == null) {
				try {
					getMethod = MethodUtils.getAccessibleMethod(cls, "get" + name);
				} catch (Exception ex) {
					getMethod = null;
				}
			}

			// 有函数的情况下，使用getter，setter；没有使用field方式访问
			if (getMethod != null) {
				try {
					setMethod = MethodUtils.getAccessibleMethod(cls,
							"set" + name.substring(0, 1).toUpperCase() + name.substring(1), getMethod.getReturnType());
				} catch (Exception ex) {
					setMethod = null;
				}

				if (setMethod == null) {
					setMethod = MethodUtils.getAccessibleMethod(cls, "set" + name, getMethod.getReturnType());
				}

			} else {
				field = FieldUtils.getDeclaredField(cls, name);
			}

		} catch (Exception ex) {
			ex.printStackTrace();
		}

		if (field == null && (getMethod == null || setMethod == null))
			throw new RuntimeException("get accessable mehtod or field fail");
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Object getValue(Object e) {

		if (getMethod != null) {
			try {
				return getMethod.invoke(e);
			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
				e1.printStackTrace();
			}
		} else if (field != null) {
			try {
				field.get(e);
			} catch (IllegalArgumentException | IllegalAccessException e1) {
				e1.printStackTrace();
			}
		}

		return null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setValue(Object e, Object v) {
		if (setMethod != null) {
			try {
				setMethod.invoke(e, v);
			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
				e1.printStackTrace();
			}
		} else if (field != null) {
			try {
				field.set(e, v);
			} catch (IllegalArgumentException | IllegalAccessException e1) {
				e1.printStackTrace();
			}
		}
	}

}
